﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using Apollo;

namespace AlgoMS
{
    public class AlgoMSStrategyFactory : IApolloStrategyFactory
    {
        public ApolloStrategy createNew(string id)
        {
            return new AlgoMSStrategy(id);
        }

    }
    public class AlgoMSStrategy : ApolloStrategy, IApolloStrategyFuncListener
    {
        private const string FUNC_REQ_MODIFY = "reqModify";

        private Dictionary<string, ApolloMdField> lastMdDict;  //上一个时刻的市场行情
        private AlgoMSContract mainContract;  //基准合约
        private Dictionary<string, AlgoMSContract> contractDict;  //该策略的所有合约

        private Dictionary<string, bool> isFirstStartBid; //第一次报买单
        private Dictionary<string, bool> isFirstStartAsk; //第一次报卖单
        private Dictionary<string, long> tradeVolBid; //当前的买头寸
        private Dictionary<string, long> tradeVolAsk; //当前的卖头寸

        private Dictionary<string, List<AlgoMSOrder>> bidOrderList; //报价合约的买订单
        private Dictionary<string, List<AlgoMSOrder>> askOrderList; //报价合约的卖订单

        private Dictionary<long, long> sumHedgingVol;    //报价合约的累计成交量,用于计算对冲
        private Dictionary<long, long> filledAmountDict;  //某笔报价合约成交了多少手

        private object lockerFirstBidFlag = new object(); //isFirstStartBid的锁
        private object lockerFirstAskFlag = new object(); //isFirstStartAsk的锁
        private object lockerBidOrder = new object();  //bidOrderList的锁
        private object lockerAskOrder = new object();  //askOrderList的锁
        private object lockerBidVol = new object();    //tradeVolBid的锁
        private object lockerAskVol = new object();    //tradeVolAsk的锁
        private object lockerHedgeVol = new object();  //sumHedgingVol的锁
        private object lockerFilledAmountDict = new object(); //filledAmount的锁

        public AlgoMSStrategy(string id)
            : base(id)
        {
            init();
        }

        private void init()
        {
            lastMdDict = new Dictionary<string, ApolloMdField>();
            contractDict = new Dictionary<string, AlgoMSContract>();
            mainContract = null;
            isFirstStartBid = new Dictionary<string, bool>();
            isFirstStartAsk = new Dictionary<string, bool>();
            tradeVolBid = new Dictionary<string, long>();
            tradeVolAsk = new Dictionary<string, long>();
            bidOrderList = new Dictionary<string, List<AlgoMSOrder>>();
            askOrderList = new Dictionary<string, List<AlgoMSOrder>>();
            sumHedgingVol = new Dictionary<long, long>();
            filledAmountDict = new Dictionary<long, long>();
        }

        public override List<Tuple<IApolloTrader, string>> getInstrumentList()
        {
            List<Tuple<IApolloTrader, string>> instrList = new List<Tuple<IApolloTrader, string>>();
            ApolloStrategy[] contractList = this.getChildStrategies();
            foreach (ApolloStrategy c in contractList)
            {
                AlgoMSContract sc = (AlgoMSContract)c;
                instrList.Add(new Tuple<IApolloTrader, string>(sc.getTrader(), sc.getInstrId()));
            }
            return instrList;
        }

        protected override bool startHandler()
        {
            ApolloGlobal.getCore().getStrategyFuncServer().registerFuncListener(this);

            ApolloStrategy[] contractList = this.getChildStrategies();
            int m = 0;
            int n = 0;
            contractDict.Clear();
            foreach (ApolloStrategy c in contractList)
            {
                AlgoMSContract contract = (AlgoMSContract)c;
                if (!contract.checkAccount())
                {
                    return false;
                }
                if (contract.getRatio() < 0)
                {
                    if (!contract.isActive())
                    {
                        ApolloGlobal.getCore().debugPrint("******警告：AlgoMS策略启动失败，基准合约未启动******");
                        return false;
                    }
                    else
                    {
                        m++;
                        mainContract = contract;
                    }
                }
                else
                {
                    lock (lockerFirstBidFlag)
                    {
                        isFirstStartBid[contract.getInstrId()] = true;
                    }
                    lock (lockerFirstAskFlag)
                    {
                        isFirstStartAsk[contract.getInstrId()] = true;
                    }

                    if (!contract.checkContract())
                    {
                        return false;
                    }
                    if (contract.isActive())
                    {
                        n++;
                    }
                    bidOrderList[contract.getInstrId()] = new List<AlgoMSOrder>();
                    askOrderList[contract.getInstrId()] = new List<AlgoMSOrder>();
                    tradeVolBid[contract.getInstrId()] = 0;
                    tradeVolAsk[contract.getInstrId()] = 0;
                }
                contractDict.Add(contract.getInstrId(), contract);
            }
            if (n == 0)
            {
                ApolloGlobal.getCore().debugPrint("******警告：AlgoMS参数设置错误，报价合约至少要有一个状态为on******");
                return false;
            }
            if (m != 1)
            {
                ApolloGlobal.getCore().debugPrint("******警告：AlgoMS参数设置错误，ratio有且只有一个可以为负数******");
                return false;
            }
            else
            {
                foreach (ApolloStrategy c in contractList)
                {
                    AlgoMSContract sc = (AlgoMSContract)c;
                    sc.startListenMD();
                }
            }
            ApolloGlobal.getCore().debugPrint("******AlgoMS策略成功启动, strategy id=[{0}]******", getId());
            return true;
        }

        protected override bool stopHandler()
        {
            ApolloGlobal.getCore().getStrategyFuncServer().removeFuncListener(this);
            ApolloStrategy[] contractList = this.getChildStrategies();
            foreach (ApolloStrategy c in contractList)
            {
                AlgoMSContract sc = (AlgoMSContract)c;
                sc.stopListenMD();
            }
            ApolloGlobal.getCore().getComplexOrderDb().rejectOrders(this.id);
            foreach (var bList in bidOrderList.Values)
            {
                bList.Clear();
            }
            foreach (var aList in askOrderList.Values)
            {
                aList.Clear();
            }
            bidOrderList.Clear();
            askOrderList.Clear();
            tradeVolBid.Clear();
            tradeVolAsk.Clear();
            sumHedgingVol.Clear();
            filledAmountDict.Clear();
            isFirstStartBid.Clear();
            isFirstStartAsk.Clear();
            ApolloGlobal.getCore().debugPrint("******AlgoMS策略成功关闭******");
            return true;
        }

        private ApolloStrategyInstrumentState getInstrumentState(string instrumentId)
        {
            return ApolloGlobal.getCore().getStatistics().getStrategyInstrumentState(getId(), instrumentId);
        }

        public void onMarketChanged(ApolloMdField data, int changeFlag)
        {
            string instrId = data.InstrumentID;

            // update last md dictionary
            ApolloMdField mainMd;

            if (!lastMdDict.TryGetValue(mainContract.getInstrId(), out mainMd))
            {
                lastMdDict[instrId] = data;
                return;
            }

            AlgoMSContract contract = contractDict[instrId];
            if (contract == mainContract)
            {
                List<Thread> tList = new List<Thread>();
                foreach (AlgoMSContract subContract in contractDict.Values)
                {
                    if (subContract != mainContract && subContract.isActive())
                    {
                        processContract(subContract, data);
                        /*
                        Thread t = new Thread(new ParameterizedThreadStart(processContract));
                        Dictionary<string, object> d = new Dictionary<string, object>();
                        d["subContract"] = subContract;
                        d["data"] = data;
                        t.Start(d);
                        tList.Add(t);
                         */
                    }
                }
                /*
                for(int i = 0; i < tList.Count; i++)
                {
                    tList[i].Join();
                }
               * */
            }

            lastMdDict[instrId] = data;
        }

        private void processContract(AlgoMSContract subContract, ApolloMdField data)
        //private void processContract(object d)
        {
            /*
            Dictionary<string, object> di = d as Dictionary<string, object>;
            AlgoMSContract subContract = di["subContract"] as AlgoMSContract;
            ApolloMdField data = di["data"] as ApolloMdField;
            */
            ApolloMdField mainMd, subMd;
            object lockerBid = new object();

            if (!lastMdDict.TryGetValue(mainContract.getInstrId(), out mainMd) ||
                 !lastMdDict.TryGetValue(subContract.getInstrId(), out subMd))
            {
                return;
            }
            ApolloGlobal.getCore().debugPrint("------ AlgoMS收到行情数据: data.Bid1=[{0}] data.Ask1=[{1}] mainMd.Bid1=[{2}] mainMd.Ask1=[{3}] sub.instr=[{4}] sub.Bid1=[{5}] sub.Ask1=[{6}]", data.BidPrice1, data.AskPrice1, mainMd.BidPrice1, mainMd.AskPrice1, subContract.getInstrId(), subMd.BidPrice1, subMd.AskPrice1);

            // 第一次启动
            bool bidFlag = true;
            bool askFlag = true;
            lock (lockerFirstBidFlag)
            {
                bidFlag = isFirstStartBid[subContract.getInstrId()];
            }
            lock (lockerFirstAskFlag)
            {
                askFlag = isFirstStartAsk[subContract.getInstrId()];
            }
            //买方向
            if (bidFlag)
            {
                long contractBid = data.BidPrice1 - (mainContract.getSellThrd() - subContract.getBuyThrd());
                ApolloGlobal.getCore().debugPrint("****** 第一次启动买单价格，data.BidPrice1=[{0}] pri.SellThrd=[{1}] mm.BuyThrd=[{2}] contractBid=[{3}]", data.BidPrice1, mainContract.getSellThrd(), subContract.getBuyThrd(), contractBid);
                if (subMd.BidPrice1 - contractBid > subContract.getBuyCheck() * subContract.getProductInfo().TickValue)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：第一次启动的买方向，MM.Bid1 - 拟报单买价 > BuyCheck，不进行操作. MM.Bid1=[{0}] 拟报单价=[{1}] check=[{2}] BuyCheck=[{3}]******", subMd.BidPrice1, contractBid, subMd.BidPrice1 - contractBid, subContract.getBuyCheck() * subContract.getProductInfo().TickValue);
                }
                else
                {
                    if (subContract.getLongLim() > 0)
                    {
                        lock (lockerFirstBidFlag)
                        {
                            isFirstStartBid[subContract.getInstrId()] = false;
                        }
                        AddOrder(subContract, contractBid, ApolloOrderDirection.Buy);
                    }
                    else
                    {
                        ApolloGlobal.getCore().debugPrint("******第一次启动的买方向, longlim=0，不买单******");
                    }
                }
            }
            else
            {
                ApolloGlobal.getCore().debugPrint("######subContract LongLim=[{0}] ShortLim=[{1}] BuyThrd=[{2}] SellThrd=[{3}] Qty=[{4}] LevelLim=[{5}] BuyCheck=[{6}] SellCheck=[{7}] Tol=[{8}] Tick=[{9}]", subContract.getLongLim(), subContract.getShortLim(), subContract.getBuyThrd(), subContract.getSellThrd(), subContract.getQty(), subContract.getLevelLim(), subContract.getBuyCheck(), subContract.getSellCheck(), subContract.getTolerance(), subContract.getProductInfo().TickValue);
                ApolloGlobal.getCore().debugPrint("######mainContract LongLim=[{0}] ShortLim=[{1}] BuyThrd=[{2}] SellThrd=[{3}] Qty=[{4}] LevelLim=[{5}] BuyCheck=[{6}] SellCheck=[{7}] Tol=[{8}] Tick=[{9}]", mainContract.getLongLim(), mainContract.getShortLim(), mainContract.getBuyThrd(), mainContract.getSellThrd(), mainContract.getQty(), mainContract.getLevelLim(), mainContract.getBuyCheck(), mainContract.getSellCheck(), mainContract.getTolerance(), subContract.getProductInfo().TickValue);

                if (subContract.getLongLim() > 0)
                {
                    processLongLim(subContract, data, mainMd, subMd);
                }

            }
            //卖方向
            if (askFlag)
            {
                long contractAsk = data.AskPrice1 - (mainContract.getBuyThrd() - subContract.getSellThrd());
                ApolloGlobal.getCore().debugPrint("****** 第一次启动卖单价格，data.AskPrice1=[{0}] pri.BuyThrd=[{1}] mm.SellThrd=[{2}] contractAsk=[{3}]", data.AskPrice1, mainContract.getBuyThrd(), subContract.getSellThrd(), contractAsk);
                if (contractAsk - subMd.AskPrice1 > subContract.getSellCheck() * subContract.getProductInfo().TickValue)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：第一次启动的卖方向，拟报单卖价 - MM.Ask1 >SellCheck，不进行操作. MM.Ask1=[{0}] 拟报单价=[{1}] check=[{2}] SellCheck=[{3}]******", subMd.AskPrice1, contractAsk, contractAsk - subMd.AskPrice1, subContract.getSellCheck() * subContract.getProductInfo().TickValue);
                }
                else
                {
                    if (subContract.getShortLim() > 0)
                    {
                        lock (lockerFirstAskFlag)
                        {
                            isFirstStartAsk[subContract.getInstrId()] = false;
                        }
                        AddOrder(subContract, contractAsk, ApolloOrderDirection.Sell);
                    }
                    else
                    {
                        ApolloGlobal.getCore().debugPrint("******第一次启动的卖方向, shortlim=0, 不卖单******");
                    }
                }
            }
            else
            {
                ApolloGlobal.getCore().debugPrint("######subContract LongLim=[{0}] ShortLim=[{1}] BuyThrd=[{2}] SellThrd=[{3}] Qty=[{4}] LevelLim=[{5}] BuyCheck=[{6}] SellCheck=[{7}] Tol=[{8}] Tick=[{9}]", subContract.getLongLim(), subContract.getShortLim(), subContract.getBuyThrd(), subContract.getSellThrd(), subContract.getQty(), subContract.getLevelLim(), subContract.getBuyCheck(), subContract.getSellCheck(), subContract.getTolerance(), subContract.getProductInfo().TickValue);
                ApolloGlobal.getCore().debugPrint("######mainContract LongLim=[{0}] ShortLim=[{1}] BuyThrd=[{2}] SellThrd=[{3}] Qty=[{4}] LevelLim=[{5}] BuyCheck=[{6}] SellCheck=[{7}] Tol=[{8}] Tick=[{9}]", mainContract.getLongLim(), mainContract.getShortLim(), mainContract.getBuyThrd(), mainContract.getSellThrd(), mainContract.getQty(), mainContract.getLevelLim(), mainContract.getBuyCheck(), mainContract.getSellCheck(), mainContract.getTolerance(), subContract.getProductInfo().TickValue);

                if (subContract.getShortLim() > 0)
                {
                    processShortLim(subContract, data, mainMd, subMd);
                }
            }

        }

        void processLongLim(AlgoMSContract subContract, ApolloMdField data, ApolloMdField mainMd, ApolloMdField subMd)
        {
            ApolloGlobal.getCore().debugPrint("******买方向, LongLim>0, instr=[{0}] LongLim=[{1}]******", subContract.getInstrId(), subContract.getLongLim());
            if (data.BidPrice1 <= 0)
            {
                return;
            }

            // 删除档位中已经成交或者撤销的订单
            // 主要是维护档位LevelLim，已经成交或者撤销的订单不占用档位
            lock (lockerBidOrder)
            {
                if (bidOrderList.ContainsKey(subContract.getInstrId()))
                {
                    for (int i = bidOrderList[subContract.getInstrId()].Count - 1; i >= 0; i--)
                    {
                        if (bidOrderList[subContract.getInstrId()][i].status == ApolloOrderStatus.AllTraded || bidOrderList[subContract.getInstrId()][i].status == ApolloOrderStatus.Canceled)
                        {
                            bidOrderList[subContract.getInstrId()].Remove(bidOrderList[subContract.getInstrId()][i]);
                        }
                    }
                    /*
                        foreach (var order in bidOrderList[subContract.getInstrId()])
                        {
                            if (order.status == ApolloOrderStatus.AllTraded || order.status == ApolloOrderStatus.Canceled)
                            {
                                bidOrderList[subContract.getInstrId()].Remove(order);
                            }
                        }
                    */
                }
            }

            long contractBid = 0;

            ApolloGlobal.getCore().debugPrint("###### data.Bid1=[{0}] data.oldBid1=[{1}] tol*tick=[{2}]######", data.BidPrice1, mainMd.BidPrice1, subContract.getTolerance() * subContract.getProductInfo().TickValue);

            // 找出当前的最大入场买价
            List<AlgoMSOrder> todoBidList = new List<AlgoMSOrder>();
            lock (lockerBidOrder)
            {
                todoBidList = bidOrderList[subContract.getInstrId()];
            }
            long base_bid;
            // 如果报价买单列表为空,情况等同第一次启动
            if (todoBidList.Count == 0)
            {
                base_bid = 0;
            }
            else
            {
                base_bid = todoBidList[0].price + (mainContract.getSellThrd() - subContract.getBuyThrd());
                for (int i = 1; i < todoBidList.Count; i++)
                {
                    long newBid = todoBidList[i].price + (mainContract.getSellThrd() - subContract.getBuyThrd());
                    if (newBid > base_bid)
                    {
                        base_bid = newBid;
                    }
                }
            }
            ApolloGlobal.getCore().debugPrint("******买方向, base_bid=[{0}]******", base_bid);
            // 条件1 new_base_bid > base_bid
            //if (data.BidPrice1 > mainMd.BidPrice1)
            if (data.BidPrice1 > base_bid)
            {
                contractBid = data.BidPrice1 - (mainContract.getSellThrd() - subContract.getBuyThrd());
                ApolloGlobal.getCore().debugPrint("******买方向，满足条件1: base_bid=[{0}] newMd.BidPrice1=[{1}] contractBid=[{2}]******", base_bid, data.BidPrice1, contractBid);

                // 根据最新的逻辑流程，满足条件1的时候也要判断是否已有报单
                lock (lockerBidOrder)
                {
                    List<AlgoMSOrder> subContractBidList = bidOrderList[subContract.getInstrId()];
                    // 找出拟报单价的挂单
                    List<AlgoMSOrder> list = subContractBidList.Where(i => i.price == contractBid).ToList();
                    if (list.Count > 0)
                    {
                        ApolloGlobal.getCore().debugPrint("******警告：买方向，拟提交的买单在对应的价格已有报单 标的=[{0}] 拟提交的买单价=[{1}]******", subContract.getInstrId(), contractBid);
                        return;
                    }
                }
            }

            // 条件2 new_base_bid < base_bid - Tolerance*Tick
            //else if (data.BidPrice1 < mainMd.BidPrice1 - subContract.getTolerance() * subContract.getProductInfo().TickValue)
            else if (data.BidPrice1 < base_bid - subContract.getTolerance() * subContract.getProductInfo().TickValue)
            {
                List<AlgoMSOrder> subContractList = new List<AlgoMSOrder>();
                lock (lockerBidOrder)
                {
                    subContractList = bidOrderList[subContract.getInstrId()];
                }
                // 撤单price > new_base_bid - (priSell-mmBuy) + Tolerance * tick
                long price = data.BidPrice1 - (mainContract.getSellThrd() - subContract.getBuyThrd()) + subContract.getTolerance() * subContract.getProductInfo().TickValue;
                List<AlgoMSOrder> cancelList = subContractList.Where(i => i.price > price).ToList();
                ApolloGlobal.getCore().debugPrint("******买方向，满足条件2: base_bid=[{0}] newMd.BidPrice1=[{1}] price=[{2}] 要撤单的数量=[{3}] ******", base_bid, data.BidPrice1, price, cancelList.Count);
                if (cancelList.Count > 0)
                {
                    for (int i = cancelList.Count - 1; i >= 0; i--)
                    {
                        AlgoMSOrder canOrder = cancelList[i];
                        ApolloOrderCancelRspCallback.monitor(canOrder,
                                (ApolloExchangeEventContext ect) =>
                                {
                                    // tradeVol是在已经成交后，计算对冲时，进行计算的，所以撤单不影响
                                    // 撤单时候只需要把单从bidOrderList删除
                                    if (canOrder.status == ApolloOrderStatus.Canceled || canOrder.status == ApolloOrderStatus.AllTraded)
                                    {
                                        // long unFilledAmount = canOrder.quantity - canOrder.filledAmount;
                                        ApolloGlobal.getCore().debugPrint("******买方向，满足条件2的撤单 instr=[{0}] price=[{1}] quantity=[{2}] fillAmount=[{3}]******", subContract.getInstrId(), canOrder.price, canOrder.quantity, canOrder.filledAmount);

                                    }
                                }, null);
                        ApolloGlobal.getCore().debugPrint("******买方向，条件2: 撤单instr=[{0}] orderRef=[{1}] price=[{2}] ******", canOrder.instrumentId, canOrder.orderRef, canOrder.price);
                        canOrder.reject();
                        lock (lockerBidOrder)
                        {
                            bidOrderList[subContract.getInstrId()].Remove(canOrder);
                        }
                    }
                }
                return;
            }
            //条件3 new_base_bid在上述区间
            else
            {
                contractBid = data.BidPrice1 - (mainContract.getSellThrd() - subContract.getBuyThrd());
                ApolloGlobal.getCore().debugPrint("******买方向，满足条件3: base_bid=[{0}] newMd.BidPrice1=[{1}] contractBid=[{2}]******", base_bid, data.BidPrice1, contractBid);
                lock (lockerBidOrder)
                {
                    List<AlgoMSOrder> subContractBidList = bidOrderList[subContract.getInstrId()];
                    // 找出拟报单价的挂单
                    List<AlgoMSOrder> list = subContractBidList.Where(i => i.price == contractBid).ToList();
                    if (list.Count > 0)
                    {
                        ApolloGlobal.getCore().debugPrint("******警告：买方向，拟提交的买单在对应的价格已有报单 标的=[{0}] 拟提交的买单价=[{1}]******", subContract.getInstrId(), contractBid);
                        return;
                    }
                }

            }
            // mm.bid1 - 拟报单买价 > buyCheck?
            long check = subMd.BidPrice1 - contractBid;
            long buyCheck = subContract.getBuyCheck() * subContract.getProductInfo().TickValue;
            if (subMd.BidPrice1 - contractBid > subContract.getBuyCheck() * subContract.getProductInfo().TickValue)
            {
                ApolloGlobal.getCore().debugPrint("******警告：买方向，MM.Bid1 - 拟报单买价 > BuyCheck，不进行操作. MM.Bid1=[{0}] 拟报单价=[{1}] check=[{2}] BuyCheck=[{3}]******", subMd.BidPrice1, contractBid, check, subContract.getBuyCheck() * subContract.getProductInfo().TickValue);
                return;
            }
            else
            {
                ApolloGlobal.getCore().debugPrint("******买方向，MM.Bid1 - 拟报单买价 <= BuyCheck，继续操作. MM.Bid1=[{0}] 拟报单价=[{1}] check=[{2}] BuyCheck=[{3}]******", subMd.BidPrice1, contractBid, check, subContract.getBuyCheck() * subContract.getProductInfo().TickValue);
            }
            // 报单后报价档位超过levelLim?
            List<AlgoMSOrder> orderList = new List<AlgoMSOrder>();
            lock (lockerBidOrder)
            {
                orderList = bidOrderList[subContract.getInstrId()];
            }
            if (orderList.Count < subContract.getLevelLim())
            {
                ApolloGlobal.getCore().debugPrint("******买方向,报单后档位不超过LevelLim, instr=[{0}] count=[{1}] LevelLim=[{2}]******", subContract.getInstrId(), orderList.Count, subContract.getLevelLim());
                AddOrder(subContract, contractBid, ApolloOrderDirection.Buy);
            }
            else
            {
                // 撤销最后一档买价(离市场行情最远的档位)
                AlgoMSOrder order = orderList[0];
                long distance = Math.Abs(order.price - subMd.BidPrice1);
                for (int i = 1; i < orderList.Count; i++)
                {
                    AlgoMSOrder bidOrder = orderList[i];
                    long dis = Math.Abs(bidOrder.price - subMd.BidPrice1);
                    if (dis >= distance)
                    {
                        distance = dis;
                        order = bidOrder;
                    }
                }
                // 如果拟报价与市场价的距离比当前档位报价距离更大，则不挂档
                if (Math.Abs(contractBid - subMd.BidPrice1) > distance)
                {
                    ApolloGlobal.getCore().debugPrint("******买方向,拟报价比当前档位中的价格距离市场价更远，不操作，contractBid=[{0}] Bid1=[{1}] worstPrice=[{2}]******", contractBid, subMd.BidPrice1, order.price);
                    return;
                }
                ApolloGlobal.getCore().debugPrint("******买方向,报单后档位超过LevelLim，撤最差档位, instr=[{0}] levelLim=[{1}] cancelOrderPrice=[{2}], newOrderPrice=[{3}]", subContract.getInstrId(), subContract.getLevelLim(), order.price, contractBid);
                // 撤单，替换新的订单
                ApolloOrderCancelRspCallback.monitor(order,
                    (ApolloExchangeEventContext cxt) =>
                    {
                        if (order.status == ApolloOrderStatus.Canceled || order.status == ApolloOrderStatus.AllTraded)
                        {
                            ApolloGlobal.getCore().debugPrint("******买方向,报单后档位超过LevelLim,替换最差档位 instr=[{0}] count=[{1}] LevelLim=[{2}] 被替换档位价格=[{3}] 新档位价格=[{4}]******", subContract.getInstrId(), orderList.Count, subContract.getLevelLim(), order.price, contractBid);
                            return;
                        }
                    }, null);

                order.reject();
                lock (lockerBidOrder)
                {
                    bidOrderList[subContract.getInstrId()].Remove(order);
                }
                ApolloGlobal.getCore().debugPrint("****** 报买单价格,data.BidPrice1=[{0}] pri.SellThrd=[{1}] mm.BuyThrd=[{2}] contractBid=[{3}]", data.BidPrice1, mainContract.getSellThrd(), subContract.getBuyThrd(), contractBid);
                AddOrder(subContract, contractBid, ApolloOrderDirection.Buy);
            }

        }


        void processShortLim(AlgoMSContract subContract, ApolloMdField data, ApolloMdField mainMd, ApolloMdField subMd)
        {
            ApolloGlobal.getCore().debugPrint("******卖方向, shortLim>0, instr=[{0}] shortLim=[{1}]******", subContract.getInstrId(), subContract.getShortLim());
            if (data.AskPrice1 <= 0)
            {
                return;
            }

            // 删除档位中已经成交或者撤销的订单
            lock (lockerAskOrder)
            {
                if (askOrderList.ContainsKey(subContract.getInstrId()))
                {
                    for (int i = askOrderList[subContract.getInstrId()].Count - 1; i >= 0; i--)
                    {
                        if (askOrderList[subContract.getInstrId()][i].status == ApolloOrderStatus.AllTraded || askOrderList[subContract.getInstrId()][i].status == ApolloOrderStatus.Canceled)
                        {
                            askOrderList[subContract.getInstrId()].Remove(askOrderList[subContract.getInstrId()][i]);
                        }
                    }
                    /*
                        foreach (var order in askOrderList[subContract.getInstrId()])
                        {
                            if (order.status == ApolloOrderStatus.AllTraded || order.status == ApolloOrderStatus.Canceled)
                            {
                                askOrderList[subContract.getInstrId()].Remove(order);
                            }
                        }
                     * */
                }

            }

            long contractAsk = 0;

            ApolloGlobal.getCore().debugPrint("###### data.Ask1=[{0}] data.oldAsk1=[{1}] tol*tick=[{2}]######", data.AskPrice1, mainMd.AskPrice1, subContract.getTolerance() * subContract.getProductInfo().TickValue);

            // 找出当前的最小入场卖价
            List<AlgoMSOrder> todoAskList = new List<AlgoMSOrder>();
            lock (lockerAskOrder)
            {
                todoAskList = askOrderList[subContract.getInstrId()];
            }
            long base_ask;
            // 如果报价买单列表为空,情况等同第一次启动
            if (todoAskList.Count == 0)
            {
                base_ask = long.MaxValue;
            }
            else
            {
                base_ask = todoAskList[0].price + (mainContract.getBuyThrd() - subContract.getSellThrd());
                for (int i = 1; i < todoAskList.Count; i++)
                {
                    long newAsk = todoAskList[i].price + (mainContract.getBuyThrd() - subContract.getSellThrd());
                    if (newAsk < base_ask)
                    {
                        base_ask = newAsk;
                    }
                }
            }
            ApolloGlobal.getCore().debugPrint("******卖方向, base_ask=[{0}]******", base_ask);
            // 条件1 new_base_ask < base_ask
            //if (data.AskPrice1 < mainMd.AskPrice1)
            if (data.AskPrice1 < base_ask)
            {
                contractAsk = data.AskPrice1 - (mainContract.getBuyThrd() - subContract.getSellThrd());
                ApolloGlobal.getCore().debugPrint("******卖方向，满足条件1: base_ask=[{0}] newMd.AskPrice1=[{1}] contractAsk=[{2}]******", base_ask, data.AskPrice1, contractAsk);

                lock (lockerAskOrder)
                {
                    // 根据最新的逻辑流程，满足条件1的时候也要判断是否已有报单
                    List<AlgoMSOrder> subContractAskList = askOrderList[subContract.getInstrId()];
                    // 找出拟报价的挂单
                    List<AlgoMSOrder> list = subContractAskList.Where(i => i.price == contractAsk).ToList();
                    if (list.Count > 0)
                    {
                        ApolloGlobal.getCore().debugPrint("******警告：卖方向，拟提交的卖单在对应的价格已有报单 拟提交的卖单价=[{0}]******", contractAsk);
                        return;
                    }
                }

            }
            // 条件2 new_base_ask > base_ask - tolerance*tick
            //else if (data.AskPrice1 > mainMd.AskPrice1 + subContract.getTolerance() * subContract.getProductInfo().TickValue)
            else if (data.AskPrice1 > base_ask + subContract.getTolerance() * subContract.getProductInfo().TickValue)
            {
                List<AlgoMSOrder> subContractList = new List<AlgoMSOrder>();
                lock (lockerAskOrder)
                {
                    subContractList = askOrderList[subContract.getInstrId()];
                }
                // 撤单price < new_base_ask - sellThrd + Tolerance * tick
                long price = data.AskPrice1 - (mainContract.getBuyThrd() - subContract.getSellThrd()) - subContract.getTolerance() * subContract.getProductInfo().TickValue;
                List<AlgoMSOrder> cancelList = subContractList.Where(i => i.price < price).ToList();
                ApolloGlobal.getCore().debugPrint("******卖方向，满足条件2: base_ask=[{0}] newMd.AskPrice1=[{1}] price=[{2}] 要撤单的数量=[{3}]******", base_ask, data.AskPrice1, price, cancelList.Count);
                if (cancelList.Count > 0)
                {
                    for (int i = cancelList.Count - 1; i >= 0; i--)
                    {
                        AlgoMSOrder canOrder = cancelList[i];
                        ApolloOrderCancelRspCallback.monitor(canOrder,
                                (ApolloExchangeEventContext ect) =>
                                {
                                    if (canOrder.status == ApolloOrderStatus.Canceled || canOrder.status == ApolloOrderStatus.AllTraded)
                                    {
                                        ApolloGlobal.getCore().debugPrint("******卖方向，满足条件2的撤单 instr=[{0}] price=[{1}] quantity=[{2}] fillAmount=[{3}]******", subContract.getInstrId(), canOrder.price, canOrder.quantity, canOrder.filledAmount);

                                        return;
                                    }
                                }, null);
                        ApolloGlobal.getCore().debugPrint("******卖方向，条件2: 撤单instr=[{0}] orderRef=[{1}] price=[{2}] ******", canOrder.instrumentId, canOrder.orderRef, canOrder.price);
                        canOrder.reject();
                        lock (lockerAskOrder)
                        {
                            askOrderList[subContract.getInstrId()].Remove(canOrder);
                        }
                    }
                }
                return;
            }
            // 条件3 
            else
            {
                contractAsk = data.AskPrice1 - (mainContract.getBuyThrd() - subContract.getSellThrd());
                ApolloGlobal.getCore().debugPrint("******卖方向，满足条件3: base_ask=[{0}] newMd.AskPrice1=[{1}] contractAsk=[{2}]******", base_ask, data.AskPrice1, contractAsk);

                lock (lockerAskOrder)
                {
                    List<AlgoMSOrder> subContractAskList = askOrderList[subContract.getInstrId()];
                    // 找出拟报单价的挂单
                    List<AlgoMSOrder> list = subContractAskList.Where(i => i.price == contractAsk).ToList();
                    if (list.Count > 0)
                    {
                        ApolloGlobal.getCore().debugPrint("******警告：卖方向，拟提交的卖单在对应的价格已有报单 拟提交的卖单价=[{0}]******", contractAsk);
                        return;
                    }
                }

            }
            // 拟报单卖价 - mm.ask1 > sellCheck?
            long check = contractAsk - subMd.AskPrice1;
            long sellCheck = subContract.getSellCheck() * subContract.getProductInfo().TickValue;
            if (contractAsk - subMd.AskPrice1 > subContract.getSellCheck() * subContract.getProductInfo().TickValue)
            {
                ApolloGlobal.getCore().debugPrint("******警告：卖方向，拟报单卖价 - MM.Ask1 > SellCheck，不进行操作. MM.Ask1=[{0}] 拟报单卖价=[{1}] check=[{2}] SellCheck=[{3}]******", subMd.AskPrice1, contractAsk, check, subContract.getSellCheck() * subContract.getProductInfo().TickValue);
                return;
            }
            else
            {
                ApolloGlobal.getCore().debugPrint("******卖方向, 拟报单卖价 - MM.Ask1 <= SellCheck，继续操作. MM.Ask1=[{0}] 拟报单卖价=[{1}] check=[{2}] SellCheck=[{3}]******", subMd.AskPrice1, contractAsk, check, subContract.getSellCheck() * subContract.getProductInfo().TickValue);
            }
            // 报单后报价档位超过levelLim?
            List<AlgoMSOrder> orderList = new List<AlgoMSOrder>();
            lock (lockerAskOrder)
            {
                orderList = askOrderList[subContract.getInstrId()];
            }
            if (orderList.Count < subContract.getLevelLim())
            {
                ApolloGlobal.getCore().debugPrint("******卖方向,报单后档位不超过LevelLim, instr=[{0}] count=[{1}] LevelLim=[{2}]******", subContract.getInstrId(), orderList.Count, subContract.getLevelLim());
                AddOrder(subContract, contractAsk, ApolloOrderDirection.Sell);
            }
            else
            {
                // 撤销最后一档买价(离市场行情最远的档位)

                AlgoMSOrder order = orderList[0];
                long distance = Math.Abs(order.price - subMd.AskPrice1);
                for (int i = 0; i < orderList.Count; i++)
                {
                    AlgoMSOrder askOrder = orderList[i];
                    long dis = Math.Abs(askOrder.price - subMd.AskPrice1);
                    if (dis >= distance)
                    {
                        distance = dis;
                        order = askOrder;
                    }
                }

                // 如果拟报价与市场价的距离比当前档位报价距离更大，则不挂档
                if (Math.Abs(contractAsk - subMd.AskPrice1) > distance)
                {
                    ApolloGlobal.getCore().debugPrint("******卖方向,拟报价比当前档位中的价格距离市场价更远，不操作，contractAsk=[{0}] Ask1=[{1}] worstPrice=[{2}]******", contractAsk, subMd.AskPrice1, order.price);
                    return;
                }
                ApolloGlobal.getCore().debugPrint("******卖方向,报单后档位超过LevelLim，撤最差档位, instr=[{0}] levelLim=[{1}] cancelOrderPrice=[{2}], newOrderPrice=[{3}]", subContract.getInstrId(), subContract.getLevelLim(), order.price, contractAsk);
                // 撤单，替换新的订单
                ApolloOrderCancelRspCallback.monitor(order,
                    (ApolloExchangeEventContext cxt) =>
                    {

                        if (order.status == ApolloOrderStatus.Canceled || order.status == ApolloOrderStatus.AllTraded)
                        {
                            ApolloGlobal.getCore().debugPrint("******卖方向,报单后档位超过LevelLim,替换最差档位 instr=[{0}] count=[{1}] LevelLim=[{2}] 被替换档位价格=[{3}] 新档位价格=[{4}]******", subContract.getInstrId(), orderList.Count, subContract.getLevelLim(), order.price, contractAsk);
                            return;

                        }
                    }, null);

                order.reject();
                // 撤单后直接下单，忽略中间时间
                lock (lockerAskOrder)
                {
                    askOrderList[subContract.getInstrId()].Remove(order);
                }
                ApolloGlobal.getCore().debugPrint("****** 报卖单价格,data.AskPrice1=[{0}] pri.BuyThrd=[{1}] mm.SellThrd=[{2}] contractAsk=[{3}]", data.AskPrice1, mainContract.getBuyThrd(), subContract.getSellThrd(), contractAsk);
                AddOrder(subContract, contractAsk, ApolloOrderDirection.Sell);
            }
        }

        public long hedgingOrder(string subContractInstr, int subRatio, long quantity, long filledAmount, long orderRef, ApolloOrderDirection dir, long price)
        {
            // LongLim/ShortLim

            long oldFilledAmount;
            lock (lockerFilledAmountDict)
            {
                if (filledAmountDict.TryGetValue(orderRef, out oldFilledAmount))
                {
                    if (dir == ApolloOrderDirection.Buy)
                    {
                        lock (lockerBidVol)
                        {
                            tradeVolBid[subContractInstr] += filledAmount - oldFilledAmount;
                        }
                    }
                    else
                    {
                        lock (lockerAskVol)
                        {
                            tradeVolAsk[subContractInstr] += filledAmount - oldFilledAmount;
                        }
                    }
                }
                else
                {
                    if (dir == ApolloOrderDirection.Buy)
                    {
                        lock (lockerBidVol)
                        {
                            tradeVolBid[subContractInstr] += filledAmount;
                        }
                    }
                    else
                    {
                        lock (lockerAskVol)
                        {
                            tradeVolAsk[subContractInstr] += filledAmount;
                        }
                    }
                }
                filledAmountDict[orderRef] = filledAmount;
            }

            // 累计成交对冲
            long hVol = 0;
            // 全部成交了
            if (quantity == 0)
            {
                lock (lockerHedgeVol)
                {
                    long tmp;
                    if (sumHedgingVol.TryGetValue(orderRef, out tmp))
                    {
                        long theoryVol = Convert.ToInt32(Math.Abs(Math.Round((decimal)(filledAmount * mainContract.getRatio() / subRatio))));
                        hVol = theoryVol - tmp;
                        sumHedgingVol.Remove(orderRef);
                    }
                    else
                    {
                        hVol = Convert.ToInt32(Math.Abs(Math.Round((decimal)(filledAmount * mainContract.getRatio() / subRatio))));
                    }
                }
                lock (lockerFilledAmountDict)
                {
                    filledAmountDict.Remove(orderRef);
                }

                // 更新bidOrderList,askOrderList
                lock (lockerBidOrder)
                {
                    List<AlgoMSOrder> bidList = bidOrderList[subContractInstr];
                    for (int i = bidList.Count - 1; i >= 0; i--)
                    {
                        if (bidList[i].price == price)
                        {
                            ApolloGlobal.getCore().debugPrint("------全部成交,移除成交买单 orderRef=[{0}] price=[{1}] instr=[{2}]------", bidList[i].orderRef, bidList[i].price, bidList[i].instrumentId);
                            bidOrderList[subContractInstr].Remove(bidList[i]);
                        }
                    }
                }
                lock (lockerAskOrder)
                {
                    List<AlgoMSOrder> askList = askOrderList[subContractInstr];
                    for (int i = askList.Count - 1; i >= 0; i--)
                    {
                        if (askList[i].price == price)
                        {
                            ApolloGlobal.getCore().debugPrint("------全部成交,移除成交卖单 orderRef=[{0}] price=[{1}] instr=[{2}]------", askList[i].orderRef, askList[i].price, askList[i].instrumentId);
                            askOrderList[subContractInstr].Remove(askList[i]);
                        }
                    }
                }


            }
            // 没有全部成交
            else
            {
                lock (lockerHedgeVol)
                {
                    long tmp;
                    if (sumHedgingVol.TryGetValue(orderRef, out tmp))
                    {
                        long theoryVol = Convert.ToInt32(Math.Abs(Math.Round((decimal)(filledAmount * mainContract.getRatio() / subRatio))));
                        hVol = theoryVol - tmp;
                        sumHedgingVol[orderRef] = theoryVol;
                    }
                    else
                    {
                        hVol = Convert.ToInt32(Math.Abs(Math.Round((decimal)(filledAmount * mainContract.getRatio() / subRatio))));
                        sumHedgingVol[orderRef] = hVol;
                    }
                }
            }
            return hVol;
        }

        public long getLastBidPrice(string instr)
        {
            return lastMdDict[instr].BidPrice1;
        }

        public long getLastAskPrice(string instr)
        {
            return lastMdDict[instr].AskPrice1;
        }

        private void AddOrder(AlgoMSContract subContract, long price, ApolloOrderDirection dir)
        {
            ApolloGlobal.getCore().debugPrint("******提交报单: Instr=[{0}] price=[{1}] dir=[{2}]******", subContract.getInstrId(), price, dir);
            if (dir == ApolloOrderDirection.Buy)
            {
                long bidV = 0;
                lock (lockerBidVol)
                {
                    bidV = tradeVolBid[subContract.getInstrId()];
                }
                if (bidV >= subContract.getLongLim())
                {
                    ApolloGlobal.getCore().debugPrint("******警告：买方向，挂单量达到longLim，不增档 instr=[{0}] tradeVolBid=[{1}] LongLim=[{2}]******", subContract.getInstrId(), bidV, subContract.getLongLim());
                    return;
                }

                long quantity = Math.Abs(subContract.getQty() * subContract.getRatio());

                AlgoMSOrder order = new AlgoMSOrder(getId(), "AlgoMS", quantity, price, dir, subContract, mainContract, this);
                order.submit(ApolloGlobal.getCore().getComplexOrderDb());

                lock (lockerBidOrder)
                {
                    bidOrderList[subContract.getInstrId()].Add(order);
                }

            }
            else
            {
                long askV = 0;
                lock (lockerAskVol)
                {
                    askV = tradeVolAsk[subContract.getInstrId()];
                }
                if (askV >= subContract.getShortLim())
                {
                    ApolloGlobal.getCore().debugPrint("******警告：卖方向，挂单量达到shortLim，不增档 instr=[{0}] tradeVolAsk=[{1}] ShortLim[{2}]******", subContract.getInstrId(), askV, subContract.getShortLim());
                    return;
                }

                long quantity = Math.Abs(subContract.getQty() * subContract.getRatio());

                AlgoMSOrder order = new AlgoMSOrder(getId(), "AlgoMS", quantity, price, dir, subContract, mainContract, this);
                order.submit(ApolloGlobal.getCore().getComplexOrderDb());

                lock (lockerAskOrder)
                {
                    askOrderList[subContract.getInstrId()].Add(order);
                }
            }

        }

        #region IApolloStrategyFuncListener
        public string[] getStrategyFuncNames()
        {
            return new string[] { FUNC_REQ_MODIFY };
        }

        public void onStrategyFuncRequest(ApolloStrategyFuncRequest request)
        {

            Dictionary<string, string> data = request.data;
            string contract_id;
            if (!data.TryGetValue("id", out contract_id))
            {
                ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，没有合约id******");
                return;
            }
            AlgoMSContract contract = null;
            foreach (KeyValuePair<string, AlgoMSContract> kvp in contractDict)
            {
                if (kvp.Value.getId() == contract_id)
                {
                    contract = kvp.Value;
                }
            }
            if (contract == null)
            {
                ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，没有找到合约ID对应的合约******");
                return;
            }

            string tmp;
            if (data.TryGetValue("Instr", out tmp))
            {
                if (string.IsNullOrEmpty(tmp))
                {
                    ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，Instr不能为空值******");
                }
                else
                {
                    contract.setParameter("Instr", tmp);
                }
            }
            if (data.TryGetValue("LongLim", out tmp))
            {
                if (int.Parse(tmp) < 0)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，LongLim必须大于等于0******");
                }
                else
                {
                    contract.setParameter("LongLim", tmp);
                }
            }
            if (data.TryGetValue("ShortLim", out tmp))
            {
                if (int.Parse(tmp) < 0)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，ShortLim必须大于等于0******");
                }
                else
                {
                    contract.setParameter("ShortLim", tmp);
                }
            }
            if (data.TryGetValue("BuyCheck", out tmp))
            {
                if (int.Parse(tmp) < 0)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，BuyCheck必须大于等于0******");
                }
                else
                {
                    contract.setParameter("BuyCheck", tmp);
                }
            }
            if (data.TryGetValue("SellCheck", out tmp))
            {
                if (int.Parse(tmp) < 0)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，SellCheck必须大于等于0******");
                }
                else
                {
                    contract.setParameter("SellCheck", tmp);
                }
            }
            if (data.TryGetValue("LevelLim", out tmp))
            {
                if (int.Parse(tmp) < 0)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，LevelLim必须大于等于0******");
                }
                else
                {
                    contract.setParameter("LevelLim", tmp);
                }
            }
            if (data.TryGetValue("Qty", out tmp))
            {
                if (int.Parse(tmp) < 0)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，Qty必须大于等于0******");
                }
                else
                {
                    contract.setParameter("Qty", tmp);
                }
            }
            if (data.TryGetValue("Tolerance", out tmp))
            {
                if (int.Parse(tmp) < 0)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，Tolerance必须大于等于0******");
                }
                else
                {
                    contract.setParameter("Tolerance", tmp);
                }
            }
            if (data.TryGetValue("on/off", out tmp))
            {
                if (tmp != "on" && tmp != "off")
                {
                    ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，on/off只能为on或者off******");
                }
                else
                {
                    contract.setParameter("on/off", tmp);
                }
            }
            long buyThrd = contract.getBuyThrd();
            long sellThrd = contract.getSellThrd();
            if (data.TryGetValue("BuyThrd", out tmp))
            {
                contract.setParameter("BuyThrd", tmp);
            }
            if (data.TryGetValue("SellThrd", out tmp))
            {
                contract.setParameter("SellThrd", tmp);
            }
            if (contract.getBuyThrd() > contract.getSellThrd())
            {
                ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，BuyThrd必须小于等于SellThrd******");
                contract.setParameter("BuyThrd", buyThrd.ToString());
                contract.setParameter("SellThrd", sellThrd.ToString());
            }

            if (data.TryGetValue("Ratio", out tmp))
            {
                int tRatio = int.Parse(tmp);
                if (tRatio == 0)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：通过redis设置AlgoMS参数错误，Ratio不能等于0******");
                    return;
                }
                else
                {
                    contract.setParameter("Ratio", tmp);
                }
            }
        }

        public void onStrategyFuncResponse(ApolloStrategyFuncResponse response)
        {

        }

        #endregion

    }
}
